package com.ibm.cloud.envcheck.kit;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import com.ibm.cloud.envcheck.bean.CopyRemoteFileToLocalParam;
import com.ibm.cloud.envcheck.bean.RemoteParam;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;

/**
 * command="scp -f "+rfile;
 * 
 * @author macky
 *
 */
public class RemoteServices {

	private ChannelExec channel;
	private Session session;
	private OutputStream out;
	private InputStream in;
	
	FileOutputStream fos = null;
	

	public static void main(String[] args) {
		CopyRemoteFileToLocalParam cp = new CopyRemoteFileToLocalParam();
		cp.setLocalDirectory("/Users/macky/test");
		cp.setRemoteFile("/root/openrc");
		cp.setHost("9.111.139.142");
		cp.setPort(22);
		cp.setUsername("root");
		cp.setPassword("macky123");
		RemoteServices rs = new RemoteServices();
		rs.handle(cp);
		System.out.println("hello, nimei");
		
	}

	public void initChannel(RemoteParam param) {
		JSch jsch = new JSch();
		try {
			session = jsch.getSession(param.getUsername(), param.getHost(), param.getPort());
			UserInfo user = new RemoteUserInfor(param.getPassword());
			session.setUserInfo(user);
			session.connect();
			channel = (ChannelExec) session.openChannel("exec");
			channel.setCommand(param.getCommand());
			out = channel.getOutputStream();
			in = channel.getInputStream();
			channel.connect();
			
		} catch (IOException e) {
			// log here
			e.printStackTrace();
		} catch (JSchException e) {
			// log here
			e.printStackTrace();
		}
	}

	public void destroy() {
		if (!channel.isClosed() && channel.isConnected()) {
			channel.disconnect();
			
		}
		if (session.isConnected()) {
			session.disconnect();
		}

	}

	private void action(CopyRemoteFileToLocalParam param) {
		try {
			byte[] buf = new byte[1024];
			// send '\0'
			buf[0] = 0;
			out.write(buf, 0, 1);
			out.flush();
			while (true) {
				int c = checkAck(in);
				if (c != 'C') {
					break;
				}
				// read '0644 '
				in.read(buf, 0, 5);
				long filesize = 0L;
				while (true) {
					if (in.read(buf, 0, 1) < 0) {
						// error
						break;
					}
					if (buf[0] == ' ')
						break;
					filesize = filesize * 10L + (long) (buf[0] - '0');
				}
				String file = null;
				for (int i = 0;; i++) {
					in.read(buf, i, 1);
					if (buf[i] == (byte) 0x0a) {
						file = new String(buf, 0, i);
						break;
					}
				}

				String prefix = null;
				if (new File(param.getLocalDirectory()).isDirectory()) {
					prefix = param.getLocalDirectory() + File.separator;
				}
				buf[0] = 0;
				out.write(buf, 0, 1);
				out.flush();

				// read a content of lfile
				fos = new FileOutputStream(prefix == null ? param.getLocalDirectory() : prefix + file);
				int foo;
				while (true) {
					if (buf.length < filesize)
						foo = buf.length;
					else
						foo = (int) filesize;
					foo = in.read(buf, 0, foo);
					if (foo < 0) {
						// error
						break;
					}
					fos.write(buf, 0, foo);
					filesize -= foo;
					if (filesize == 0L)
						break;
				}
				fos.close();
				fos = null;

				if (checkAck(in) != 0) {
					//System.exit(0);
					//in.close();
					return;
				}

				// send '\0'
				buf[0] = 0;
				out.write(buf, 0, 1);
				out.flush();
				//System.exit(0);
				//out.close();
				return;
			}
		} catch (Exception e) {

		}

	}

	public void handle(CopyRemoteFileToLocalParam param) {
		initChannel(param);
		action(param);
		destroy();
	}

	static int checkAck(InputStream in) throws IOException {
		int b = in.read();
		// b may be 
		// 0 for success,
		// 1 for error,
		// 2 for fatal error,
		// -1
		if (b == 0)
			return b;
		if (b == -1)
			return b;

		if (b == 1 || b == 2) {
			StringBuffer sb = new StringBuffer();
			int c;
			do {
				c = in.read();
				sb.append((char) c);
			} while (c != '\n');
			if (b == 1) { // error
				System.out.print(sb.toString());
			}
			if (b == 2) { // fatal error
				System.out.print(sb.toString());
			}
		}
		return b;
	}

	private class RemoteUserInfor implements UserInfo {
		private String passwd;

		public RemoteUserInfor(String passwd) {
			this.passwd = passwd;
		}

		@Override
		public String getPassphrase() {

			return null;
		}

		@Override
		public String getPassword() {
			return passwd;
		}

		@Override
		public boolean promptPassphrase(String arg0) {

			return false;
		}

		@Override
		public boolean promptPassword(String arg0) {
			return true;
		}

		@Override
		public boolean promptYesNo(String arg0) {
			return true;
		}

		@Override
		public void showMessage(String arg0) {
		}
	}

}
